package com.mmr.dxp.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.mmr.dxp.domain.DataTobePushed;
import com.mmr.dxp.domain.RdsResourceApprovalSuggest;
import com.mmr.dxp.domain.RdsResourceObject;
import com.mmr.dxp.mapper.DataTobePushedMapper;
import com.mmr.dxp.mapper.RdsResourceApprovalMapper;
import com.mmr.dxp.service.DxpBlockChainSupportService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.Arrays;

@Slf4j
@Service
public class DxpBlockChainSupportServiceImpl implements DxpBlockChainSupportService {
    @Value("${api.url.host}")
    private String host;
    @Value("${api.url.dxp.dxpRegisteResourceUpload}")
    private String dxpRegisteResourceUploadUrl;
    @Value("${api.url.dxp.dxpAuditResourceUpload}")
    private String dxpAuditResourceUploadUrl;
    @Value("${api.url.dxp.dxpReleaseResourceUpload}")
    private String dxpReleaseResourceUploadUrl;
    @Value("${api.url.dxp.dxpRevokeResourceUpload}")
    private String dxpRevokeResourceUploadUrl;
    @Value("${api.url.dxp.dxpResourceExchangeRecordUpload}")
    private String dxpResourceExchangeRecordUploadUrl;
    @Value("${api.url.dxp.dxpResourceInvokeStatistics}")
    private String dxpResourceInvokeStatisticsUrl;
    @Value("${api.url.dxp.dxpLoginUpload}")
    private String dxpLoginUploadUrl;
    @Value("${api.url.dxp.dxpOperationLogUpload}")
    private String dxpOperationLogUploadUrl;

    @Autowired
    private RestTemplate restTemplate;
    @Resource
    private RdsResourceApprovalMapper rdsResourceApprovalMapper;
    @Resource
    private DataTobePushedMapper dataTobePushedMapper;

    /**
     * DXP交换系统部门用户注册文件、文件夹、库表资源上链
     *
     * @param dataJsonStr dxp上链前待处理数据
     */
    @Override
    @Async
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 1.5))
    public void dxpRegisteResourceUpload(String dataJsonStr) {
        String remoteUrl = assembledRemoteUrl(host, dxpRegisteResourceUploadUrl);
        log.info("remoteUrl:" + remoteUrl);
        String callType = "POST";
        HttpEntity<String> formEntity = (HttpEntity<String>) EncapsulateCallParam(callType, dataJsonStr);
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(remoteUrl, formEntity, String.class);
        log.info("API-DXP:dxpRegisteResourceUpload---远程调用上链返回结果:" + responseEntity.getBody());
    }

    /**
     * DXP交换系统部门用户审核文件、文件夹、库表资源上链
     *
     * @param dataJsonStr dxp上链前待处理数据
     */
    @Override
    @Async
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 1.5))
    public void dxpAuditResourceUpload(String dataJsonStr) {
        JSONObject dataJsonObj = JSON.parseObject(dataJsonStr);
        String approveId = dataJsonObj.getString("approveId");
        Assert.notNull(approveId, "审批信息中的主键不能为空");
        RdsResourceApprovalSuggest rdsResourceApprovalSuggest = rdsResourceApprovalMapper.selectByPrimaryKey(approveId);
        RdsResourceObject rdObj = rdsResourceApprovalSuggest.getResource();
        Assert.notNull(rdObj, "审批信息：" + approveId + "中的资源信息不能为空");
        dataJsonObj.put("resourceId", rdObj.getId());
        dataJsonObj.put("resourceName", rdObj.getName());
        dataJsonObj.remove("approveId");
        dataJsonStr = dataJsonObj.toJSONString();
        String remoteUrl = assembledRemoteUrl(host, dxpAuditResourceUploadUrl);
        log.info("remoteUrl:" + remoteUrl);
        String callType = "POST";
        HttpEntity<String> formEntity = (HttpEntity<String>) EncapsulateCallParam(callType, dataJsonStr);
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(remoteUrl, formEntity, String.class);
        log.info("API-DXP:dxpAuditResourceUpload---远程调用上链返回结果:" + responseEntity.getBody());
    }

    /**
     * DXP交换系统部门用户发布文件、文件夹、库表资源上链
     *
     * @param dataJsonStr dxp上链前待处理数据
     */
    @Override
    @Async
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 1.5))
    public void dxpReleaseResourceUpload(String dataJsonStr) {
        String remoteUrl = assembledRemoteUrl(host, dxpReleaseResourceUploadUrl);
        log.info("remoteUrl:" + remoteUrl);
        String callType = "POST";
        HttpEntity<String> formEntity = (HttpEntity<String>) EncapsulateCallParam(callType, dataJsonStr);
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(remoteUrl, formEntity, String.class);
        log.info("API-DXP:dxpReleaseResourceUpload---远程调用上链返回结果:" + responseEntity.getBody());
    }

    /**
     * DXP交换系统部门用户撤销文件、文件夹、库表资源上链
     *
     * @param dataJsonStr dxp上链前待处理数据
     */
    @Override
    @Async
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 1.5))
    public void dxpRevokeResourceUpload(String dataJsonStr) {
        String remoteUrl = assembledRemoteUrl(host, dxpRevokeResourceUploadUrl);
        log.info("remoteUrl:" + remoteUrl);
        String callType = "POST";
        HttpEntity<String> formEntity = (HttpEntity<String>) EncapsulateCallParam(callType, dataJsonStr);
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(remoteUrl, formEntity, String.class);
        log.info("API-DXP:dxpRevokeResourceUpload---远程调用上链返回结果:" + responseEntity.getBody());
    }

    /**
     * DXP交换系统库表、文件及文件夹资源全过程操作日志上链
     */
    @Override
    @Async
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 1.5))
    public void dxpResourceProcessOperation(String dataJsonStr) {
        String remoteUrl = assembledRemoteUrl(host,dxpOperationLogUploadUrl );
        log.info("remoteUrl:" + remoteUrl);
        String callType = "POST";
        HttpEntity<String> formEntity = (HttpEntity<String>) EncapsulateCallParam(callType, dataJsonStr);
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(remoteUrl, formEntity, String.class);
        log.info("API-DXP:dxpRevokeResourceUpload---远程调用上链返回结果:" + responseEntity.getBody());
    }

    /**
     * DXP交换系统资源交换记录上链
     *
     * @param dataJsonStr
     * @return
     */
    @Override
    @Async
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 1.5))
    public void dxpResourceExchangeRecordUpload(String dataJsonStr) {
        String remoteUrl = assembledRemoteUrl(host, dxpResourceExchangeRecordUploadUrl);
        log.info("remoteUrl:" + remoteUrl);
        String callType = "POST";
        HttpEntity<String> formEntity = (HttpEntity<String>) EncapsulateCallParam(callType, dataJsonStr);
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(remoteUrl, formEntity, String.class);
        log.info("API-DXP:dxpResourceExchangeRecordUpload---远程调用上链返回结果:" + responseEntity.getBody());
    }

    /**
     * DXP资源发布量、订阅数、交换总量上链接口
     *
     * @param dataJsonStr
     */
    @Override
    @Async
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 1.5))
    public void dxpResourceInvokeStatistics(String dataJsonStr) {
        String remoteUrl = assembledRemoteUrl(host, dxpResourceInvokeStatisticsUrl);
        log.info("remoteUrl:" + remoteUrl);
        String callType = "POST";
        HttpEntity<String> formEntity = (HttpEntity<String>) EncapsulateCallParam(callType, dataJsonStr);
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(remoteUrl, formEntity, String.class);
        log.info("API-DXP:dxpResourceInvokeStatistics---远程调用上链返回结果:" + responseEntity.getBody());
    }
    /**
     * DXP部门用户登入访问交换系统信息上链
     *
     * @param dataJsonStr
     */
    @Override
    @Async
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 1.5))
    public void dxLoginUpload(String dataJsonStr) {
        String remoteUrl = assembledRemoteUrl(host, dxpLoginUploadUrl);
        log.info("remoteUrl:" + remoteUrl);
        String callType = "POST";
        HttpEntity<String> formEntity = (HttpEntity<String>) EncapsulateCallParam(callType, dataJsonStr);
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(remoteUrl, formEntity, String.class);
        log.info("API-DXP:dxLoginUpload---远程调用上链返回结果:" + responseEntity.getBody());
    }
    /**
     * callback for service api call failed
     *
     * @param e
     * @param data
     */
    @Recover
    public void smpServiceMethodRecover(Exception e, String data) {
        StackTraceElement[] elements = e.getStackTrace();
        Arrays.stream(elements).forEach(stackTrace -> {
            if ("DxpBlockChainSupportServiceImpl.java".equals(stackTrace.getFileName())){
                DataTobePushed dataTobePushed = DataTobePushed.builder()
                        .className(DxpBlockChainSupportServiceImpl.class.getName())
                        .methodName(stackTrace.getMethodName())
                        .reqBody(data).build();
                dataTobePushedMapper.save(dataTobePushed);
            }
        });
    }

    /**
     * 封装远程调用参数
     *
     * @param callType    请求类型
     * @param dataJsonStr 封装数据
     * @return
     */
    public <T> Object EncapsulateCallParam(String callType, String dataJsonStr) {
        String POST = "POST";
        if (POST.equals(callType)) {
            HttpHeaders headers = new HttpHeaders();
            MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
            headers.setContentType(type);
            headers.add("Accept", MediaType.APPLICATION_JSON.toString());
            log.info("远程调用传递参数:");
            log.info("headers:" + headers);
            log.info("body:" + dataJsonStr);
            HttpEntity<String> formEntity = new HttpEntity<>(dataJsonStr, headers);
            return formEntity;
        }
        return null;
    }

    /**
     * 封装远程调用Url
     *
     * @param host       请求域名
     * @param specifyUrl 指定apiURl
     * @return
     */
    public String assembledRemoteUrl(String host, String specifyUrl) {
        return host + specifyUrl;
    }
}
